package com.wlsk.license.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.wlsk.license.common.constant.CharteredLicenseConstant;
import com.wlsk.license.common.converter.MultipartFileConverter;
import com.wlsk.license.common.enums.CharterPlateProductTypeEnum;
import com.wlsk.license.common.enums.CharterPlateStatusEnum;
import com.wlsk.license.common.enums.OperateLogTempEnum;
import com.wlsk.license.common.exception.BusinessException;
import com.wlsk.license.common.result.Result;
import com.wlsk.license.common.utils.FileUtils;
import com.wlsk.license.dao.entity.Plate;
import com.wlsk.license.dao.entity.PlateLine;
import com.wlsk.license.dto.request.GeneratePlateReqDto;
import com.wlsk.license.dto.request.PlateBaseReqDto;
import com.wlsk.license.dto.response.DictDataResultDto;
import com.wlsk.license.dto.response.GenerateCheckDetailResultDto;
import com.wlsk.license.dto.response.GeneratePlateResDto;
import com.wlsk.license.dto.response.SignEnterpriseInfo;
import com.wlsk.license.dto.response.feign.OssObjectInfoResultDto;
import com.wlsk.license.dto.zz.BackLicenseReqDto;
import com.wlsk.license.dto.zz.GenerateElectronCharterDto;
import com.wlsk.license.dto.zz.GenerateElectronCharterReq;
import com.wlsk.license.service.*;
import com.wlsk.license.service.esign.ESignService;
import com.wlsk.license.service.feign.PlatOssFeignClient;
import com.wlsk.license.service.zpff.CharterApplyLicense;
import com.wlsk.license.service.zpff.RtabHelper;
import com.wlsk.license.service.zpff.RtabResultCode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.Map;

@Service
public class PlateGenerateServiceImpl extends BaseService implements IPlateGenerateService {

    private static final Logger log = LoggerFactory.getLogger(PlateGenerateServiceImpl.class);
    @Autowired
    private IPlateService plateService;
    @Autowired
    private ISysDictService dictService;
    @Autowired
    private IPlateLineService lineService;
    @Autowired
    private ESignService eSignService;
    @Autowired
    private IAuthenticationService authenticationService;
    @Autowired
    private IFileUploadService fileUploadService;

    @Override
    public GenerateCheckDetailResultDto checkDetail(PlateBaseReqDto reqDto) {
        GenerateCheckDetailResultDto resDto = new GenerateCheckDetailResultDto();
        Plate plate = plateService.getBaseMapper().selectById(reqDto.getPlateId());
        if(plate == null){
            throw new BusinessException("包车牌申请不存在!");
        }
        if(!plate.getCharterPlateStatus().equals(CharterPlateStatusEnum.REVIEWED.getCode())) {
            throw new BusinessException("包车牌申请状态不支持生成包车牌，请确认！");
        }
        BeanUtils.copyProperties(plate, resDto);
        PlateLine plateLine = lineService.getBaseMapper().selectById(reqDto.getPlateId());
        resDto.setTotalMileage(plateLine.getTotalMileage());
        resDto.setStartPlace(plateLine.getStartPlace());
        resDto.setEndPlace(plateLine.getEndPlace());
        DictDataResultDto dict = dictService.getOneByTypeAndValue("plate_transport_mark", plateLine.getCardType());
        if(dict != null){
            resDto.setPlateTransportMark(dict.getDictLabel());
        }
        return resDto;
    }

    /**
     * 生成包车牌 1.生成电子包车牌 2.下载电子包车牌 3.签章 4.盖章后回传电子包车牌（已签章）
     * @param reqDto
     */
    @Transactional
    @Override
    public GeneratePlateResDto generatePlate(GeneratePlateReqDto reqDto) {
        GeneratePlateResDto resDto = new GeneratePlateResDto();
        Long plateId = reqDto.getPlateId();
        Plate plate = plateService.getBaseMapper().selectById(plateId);
        PlateLine plateLine = lineService.getBaseMapper().selectById(plateId);
        String orgOperatorCode = authenticationService.findOrgOperatorCode(plate.getOrgId(), 2);
        validateGenerateParam(plate, reqDto, orgOperatorCode);
        /* 1、生成包车牌 **/
        GenerateElectronCharterReq req = GenerateElectronCharterReq.builder().appnumber(plate.getTradeAppNumber()).operatorcode(orgOperatorCode).cardtype(plateLine.getCardType()).type(String.valueOf(plate.getPlateProduceType())).charternumber(Integer.valueOf(reqDto.getPaperPlateNumber())).build();
        GenerateElectronCharterDto dto = CharterApplyLicense.requestCharterLicenseData(req, CharterApplyLicense.APPLY_ELECTRONIC_LICPLA_URL, GenerateElectronCharterDto.class);
        if(dto == null || StringUtils.isEmpty(dto.getFilepath())){
            throw new BusinessException("生成电子包车牌失败");
        }
        /* 2、下载电子包车牌 */
        try {
            byte[] bytes = RtabHelper.downloadFromTransportation(dto.getFilepath());
            Result<OssObjectInfoResultDto> result = null;
            if(plate.getPlateProduceType().equals(CharterPlateProductTypeEnum.ELECTRONIC_CHARTER_PLATE.getCode())) { // 电子包车牌
                /* 3、签章 */
                SignEnterpriseInfo signEnterpriseInfo = authenticationService.findEnterpriseInfo(plate.getOrgId());
                if(StringUtils.isEmpty(signEnterpriseInfo.getAccountId()) || StringUtils.isEmpty(signEnterpriseInfo.getSealData())){
                    log.info("企业签章信息不存在，请联系管理员！{}", plate.getOrgId());
                    throw new BusinessException("企业签章信息不存在，请联系管理员！");
                }
                String pdfRootPath = createPdfFolderInRoot();
                String srcPdfFile = pdfRootPath + File.separator + plateId + "-" + (System.currentTimeMillis()) + ".pdf";
                String dstPdfFile = pdfRootPath + File.separator + plateId + "-" + (System.currentTimeMillis()) + "-dst.pdf";
                FileUtils.createFileFromBytes(bytes, srcPdfFile);
                eSignService.plateESign(signEnterpriseInfo.getSealData(), signEnterpriseInfo.getAccountId(), srcPdfFile, dstPdfFile);
                /* 上传oss **/
                result = fileUploadService.uploadOss(MultipartFileConverter.convert(new File(dstPdfFile)));
                if(result.isSuccess() && result.getData() != null && StringUtils.isNotEmpty(result.getData().getUrl())) {
                    /* 4、盖章后回传电子包车牌（已签章） */
                    BackLicenseReqDto backReq = BackLicenseReqDto.builder().appnumber(plate.getTradeAppNumber()).operatorcode(orgOperatorCode).printLicPlaID(dto.getPrintLicPlaID()).cardType(plateLine.getCardType()).base64Content(FileUtils.encodeLargeFileToBase64(new File(
                            dstPdfFile))).build();
                    Map<String, String> backRes = CharterApplyLicense.gainCharterLicenseData(JSONObject.toJSONString(backReq), CharterApplyLicense.REBACK_ELECTRONIC_LICPLA_URL);
                    if(backRes.get("code").equals(RtabResultCode.SUCCESS.code())) {
                        log.info("生成电子包车牌成功-{}", reqDto);
                        resDto.setPlateUrl(result.getData().getUrl());
                    }
                } else {
                    throw new BusinessException("上传电子包车牌到文件系统失败");
                }
            } else {  // 纸质包车牌
                /* 上传oss **/
                result = fileUploadService.uploadOss(MultipartFileConverter.convert(bytes, getFilePathName(dto.getFilepath())));
            }
            if(result != null && result.isSuccess() && result.getData() != null && StringUtils.isNotEmpty(result.getData().getUrl())) {
                plate.setPrintLicPlaId(dto.getPrintLicPlaID());
                plate.setLocalFilePath(String.valueOf(result.getData().getId()));
                plate.setCharterPlateStatus(CharterPlateStatusEnum.GENERATED.getCode());
                plate.setCharterPlateNumber(reqDto.getPaperPlateNumber());
                plate.setTradeCharterPlateStatus(CharteredLicenseConstant.TRADE_PLATE_STATUS.get(CharterPlateStatusEnum.GENERATED));
                plate.setSealStatus(plate.getPlateProduceType().equals(CharterPlateProductTypeEnum.ELECTRONIC_CHARTER_PLATE.getCode()) ? 1 : 0);
                plateService.getBaseMapper().updateById(plate);
                resDto.setPlateUrl(result.getData().getUrl());
                log.info("生成纸质包车牌成功-{}", reqDto);
                super.addOperateLog(reqDto.getPlateId(), reqDto.getUid(), OperateLogTempEnum.GENERATE_LICENSE, false);
            } else {
                throw new BusinessException("上传电子包车牌到文件系统失败");
            }
        } catch (Exception e) {
            log.error("下载电子包车牌失败:{}", dto, e);
            throw new BusinessException("下载电子包车牌失败");
        }
        return resDto;
    }

    /**
     * 在项目根目录创建文件夹
     */
    private String createPdfFolderInRoot() {
        try {
            // 获取项目根目录
            String rootPath = new File("").getAbsolutePath();
            File folder = new File(rootPath, "platePdf");
            if(!folder.exists()) {
                if (folder.mkdirs()) {
                    return folder.getAbsolutePath();
                } else {
                    throw new RuntimeException("无法创建文件夹: " + folder.getAbsolutePath());
                }
            } else {
                return folder.getAbsolutePath();
            }
        } catch (Exception e) {
            log.error("创建文件夹失败", e);
            throw new BusinessException("创建文件夹失败");
        }
    }

    /**
     * 验证参数
     * @param plate
     * @param reqDto
     */
    private void validateGenerateParam(Plate plate, GeneratePlateReqDto reqDto, String orgOperatorCode) {
        if(plate == null){
            throw new BusinessException("包车牌申请不存在!");
        }
        if(!plate.getCharterPlateStatus().equals(CharterPlateStatusEnum.REVIEWED.getCode())) {
            throw new BusinessException("包车牌申请状态不支持生成包车牌，请确认！");
        }
        if(plate.getPlateProduceType().equals(CharterPlateProductTypeEnum.PAPER_CHARTER_PLATE.getCode()) && StringUtils.isEmpty(reqDto.getPaperPlateNumber())){
            throw new BusinessException("纸质包车牌编号不能为空！");
        }
        if(StringUtils.isEmpty(orgOperatorCode)){
            throw new BusinessException("商家未绑定行业证牌系统账号，请联系管理员！");
        }
    }

    private String getFilePathName(String filePath) {
        if(filePath.contains("/")) {
            return filePath.substring(filePath.lastIndexOf("/") + 1);
        }
        return "";
    }
}
